package com.gitee.feizns.reflect;

import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.function.IntFunction;

/**
 * @author feizns
 * @since 2019/5/19 0019
 */
public abstract class ConstructorUtils {

    /**
     * 实例化一片...
     * @param generator
     * @param classes
     * @param <T>
     * @return
     */
    public static final <T> T[] newInstances(IntFunction<T[]> generator, Class<?>... classes) {
        return Arrays.stream(classes).map(ConstructorUtils::newInstance).toArray(generator);
    }

    /**
     * 实例化
     * @param type
     * @param params
     * @param <T>
     * @return
     */
    public static final <T> T newInstance(Class<T> type, Object... params) {
        try {
            return (T) get(type, ClassUtils.getClasses(params)).newInstance(params);
        } catch (ReflectiveOperationException e) {
            return null;
        }
    }

    /**
     * ..
     * @param type
     * @param params
     * @param <T>
     * @return
     */
    public static final <T> T declaredInstance(Class<T> type, Object... params) {
        Constructor<T> constructor = getDeclared(type, ClassUtils.getClasses(params));
        try {
            constructor.setAccessible(true);
            return constructor.newInstance(params);
        } catch (ReflectiveOperationException e) {
            return null;
        }
    }

    /**
     * 获取构造方法
     * @param obj
     * @param parameterTypes
     * @return
     */
    public static final Constructor getDeclared(Object obj, Class<?>... parameterTypes) {
        return getDeclared(obj.getClass(), parameterTypes);
    }

    /**
     * 获取方法
     *
     * @param type
     * @param parameterTypes
     * @return
     */
    public static final Constructor getDeclared(Class<?> type, Class<?>... parameterTypes) {
        while (type != null) {
            try {
                return type.getDeclaredConstructor(parameterTypes);
            } catch (NoSuchMethodException e) {
                type = type.getSuperclass();
            }
        }
        return null;
    }

    /**
     * 获取公共构造方法
     * @param obj
     * @param parameterTypes
     * @return
     */
    public static final Constructor get(Object obj, Class<?>... parameterTypes) {
        return get(obj.getClass(),  parameterTypes);
    }

    /**
     * 获取公共构造方法
     * @param type
     * @param parameterTypes
     * @return
     */
    public static final Constructor get(Class<?> type, Class<?>... parameterTypes) {
        try {
            return type.getConstructor(parameterTypes);
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

}
